package com.store.satring.dos;
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.Column;
import javax.validation.constraints.NotNull;

import java.util.Date;

import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Version;

import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.format.annotation.DateTimeFormat;

import com.store.satring.utils.StoreUtility;

import javax.persistence.ManyToOne;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.ManyToMany;

@Entity
@Configurable
public class GeneralLedger {

    /**
     */
    @NotNull
    @Column(unique = true)
    private Integer glNo;

    /**
     */
    @NotNull
    @Temporal(TemporalType.TIMESTAMP)
    @DateTimeFormat(style = "M-")
    private Date glDate;

    /**
     */
    @NotNull
    @ManyToOne
    private Invoice invoice;

    /**
     */
    private double invoiceAmount;

    /**
     */
    private double advanceAmount;

    /**
     */
    private double totalPaymentReceived;

    /**
     */
    private double adjustedAmount;

    /**
     */
    private double balanceAmount;

    /**
     */
    private String description;

    /**
     */
    @ManyToMany(cascade = CascadeType.ALL)
    private List<GeneralLedgerDetail> generalLedgerDetails = new ArrayList<GeneralLedgerDetail>();

	public String toString() {
        return ReflectionToStringBuilder.toString(this, ToStringStyle.SHORT_PREFIX_STYLE);
    }

	@Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    private Long id;

	@Version
    @Column(name = "version")
    private Integer version;

	public Long getId() {
        return this.id;
    }

	public void setId(Long id) {
        this.id = id;
    }

	public Integer getVersion() {
        return this.version;
    }

	public void setVersion(Integer version) {
        this.version = version;
    }

	public Integer getGlNo() {
        return this.glNo;
    }

	public void setGlNo(Integer glNo) {
        this.glNo = glNo;
    }

	public Date getGlDate() {
        return this.glDate;
    }

	public void setGlDate(Date glDate) {
        this.glDate = glDate;
    }

	public Invoice getInvoice() {
        return this.invoice;
    }

	public void setInvoice(Invoice invoice) {
        this.invoice = invoice;
    }

	public double getInvoiceAmount() {
        return this.invoiceAmount;
    }

	public void setInvoiceAmount(double invoiceAmount) {
        this.invoiceAmount = StoreUtility.getAmount(2, invoiceAmount);
    }

	public double getAdvanceAmount() {
        return this.advanceAmount;
    }

	public void setAdvanceAmount(double advanceAmount) {
        this.advanceAmount = StoreUtility.getAmount(2, advanceAmount);
    }

	public double getTotalPaymentReceived() {
        return this.totalPaymentReceived;
    }

	public void setTotalPaymentReceived(double totalPaymentReceived) {
        this.totalPaymentReceived = StoreUtility.getAmount(2, totalPaymentReceived);
    }

	public double getAdjustedAmount() {
        return this.adjustedAmount;
    }

	public void setAdjustedAmount(double adjustedAmount) {
        this.adjustedAmount = StoreUtility.getAmount(2, adjustedAmount);
    }

	public double getBalanceAmount() {
        return this.balanceAmount;
    }

	public void setBalanceAmount(double balanceAmount) {
        this.balanceAmount = StoreUtility.getAmount(2, balanceAmount);
    }

	public String getDescription() {
        return this.description;
    }

	public void setDescription(String description) {
        this.description = description;
    }

	public List<GeneralLedgerDetail> getGeneralLedgerDetails() {
        return this.generalLedgerDetails;
    }

	public void setGeneralLedgerDetails(List<GeneralLedgerDetail> generalLedgerDetails) {
        this.generalLedgerDetails = generalLedgerDetails;
    }

	@PersistenceContext
    transient EntityManager entityManager;

	public static final List<String> fieldNames4OrderClauseFilter = java.util.Arrays.asList("glNo", "glDate", "invoice", "invoiceAmount", "advanceAmount", "totalPaymentReceived", "adjustedAmount", "balanceAmount", "description", "generalLedgerDetails");

	public static final EntityManager entityManager() {
        EntityManager em = new GeneralLedger().entityManager;
        if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
        return em;
    }

	public static long countGeneralLedgers() {
        return entityManager().createQuery("SELECT COUNT(o) FROM GeneralLedger o", Long.class).getSingleResult();
    }

	public static List<GeneralLedger> findAllGeneralLedgers() {
        return entityManager().createQuery("SELECT o FROM GeneralLedger o", GeneralLedger.class).getResultList();
    }

	public static List<GeneralLedger> findAllGeneralLedgers(String sortFieldName, String sortOrder) {
        String jpaQuery = "SELECT o FROM GeneralLedger o";
        if (fieldNames4OrderClauseFilter.contains(sortFieldName)) {
            jpaQuery = jpaQuery + " ORDER BY " + sortFieldName;
            if ("ASC".equalsIgnoreCase(sortOrder) || "DESC".equalsIgnoreCase(sortOrder)) {
                jpaQuery = jpaQuery + " " + sortOrder;
            }
        }
        return entityManager().createQuery(jpaQuery, GeneralLedger.class).getResultList();
    }

	public static GeneralLedger findGeneralLedger(Long id) {
        if (id == null) return null;
        return entityManager().find(GeneralLedger.class, id);
    }

	public static List<GeneralLedger> findGeneralLedgerEntries(int firstResult, int maxResults) {
        return entityManager().createQuery("SELECT o FROM GeneralLedger o", GeneralLedger.class).setFirstResult(firstResult).setMaxResults(maxResults).getResultList();
    }

	public static List<GeneralLedger> findGeneralLedgerEntries(int firstResult, int maxResults, String sortFieldName, String sortOrder) {
        String jpaQuery = "SELECT o FROM GeneralLedger o";
        if (fieldNames4OrderClauseFilter.contains(sortFieldName)) {
            jpaQuery = jpaQuery + " ORDER BY " + sortFieldName;
            if ("ASC".equalsIgnoreCase(sortOrder) || "DESC".equalsIgnoreCase(sortOrder)) {
                jpaQuery = jpaQuery + " " + sortOrder;
            }
        }
        return entityManager().createQuery(jpaQuery, GeneralLedger.class).setFirstResult(firstResult).setMaxResults(maxResults).getResultList();
    }

	@Transactional
    public void persist() {
        if (this.entityManager == null) this.entityManager = entityManager();
        this.entityManager.persist(this);
    }

	@Transactional
    public void remove() {
        if (this.entityManager == null) this.entityManager = entityManager();
        if (this.entityManager.contains(this)) {
            this.entityManager.remove(this);
        } else {
            GeneralLedger attached = GeneralLedger.findGeneralLedger(this.id);
            this.entityManager.remove(attached);
        }
    }

	@Transactional
    public void flush() {
        if (this.entityManager == null) this.entityManager = entityManager();
        this.entityManager.flush();
    }

	@Transactional
    public void clear() {
        if (this.entityManager == null) this.entityManager = entityManager();
        this.entityManager.clear();
    }

	@Transactional
    public GeneralLedger merge() {
        if (this.entityManager == null) this.entityManager = entityManager();
        GeneralLedger merged = this.entityManager.merge(this);
        this.entityManager.flush();
        return merged;
    }
	
	public static Integer getNewGLNo() {
		Query createNativeQuery = entityManager()
				.createNativeQuery(
						"select gl_no from general_ledger order by gl_no desc limit 1");
		Object singleResult = null;
		try {
			singleResult = createNativeQuery.getSingleResult();
		} catch (Exception exp) {
			exp.printStackTrace();
		}
		if (singleResult == null) {
			return 1;
		}
		return ((Integer) singleResult) + 1;
	}

	public static Integer getGLNo(long invoiceId) {
		Query createNativeQuery = entityManager()
				.createNativeQuery(
						"select gl_no from general_ledger  where invoice = "+invoiceId+" order by gl_no desc limit 1");
		Object singleResult = null;
		try {
			singleResult = createNativeQuery.getSingleResult();
		} catch (Exception exp) {
			exp.printStackTrace();
		}
		if (singleResult == null) {
			return null;
		}
		return (Integer)singleResult;
	}
	public static List<GeneralLedger> findGLByGLNoEquals(String searchData) {
        if (searchData == null) throw new IllegalArgumentException("The argument is required");
        
        EntityManager em = Invoice.entityManager();
        String jpaQuery = " select gl.id from invoice inv " +
        				  " inner join general_ledger gl on gl.invoice = inv.id " +
        				  " inner join customer cus on cus.id = inv.customer and cus.store = 0 "+
        				  "	where  inv.invoice_no like '%"+searchData+"%' "
        				  + " OR cus.address like '%"+searchData+"%' "
        				  + " OR cus.name like '%"+searchData+"%' "
        				  + " OR cus.mobile_no like '%"+searchData+"%'  "
        				  + " OR inv.site_for like '%"+searchData+"%'"
        				  + " OR gl.gl_no like '%"+searchData+"%'";
        List resultList = em.createNativeQuery(jpaQuery).getResultList();
        List<GeneralLedger> gls = new ArrayList<GeneralLedger>();
        for (Object object : resultList) {
        	gls.add(GeneralLedger.findGeneralLedger(Long.parseLong(object.toString())));
		}
        return gls;
    }

}
